﻿namespace SP2010.Enhancements.SEO
{    
    using System;
    using System.IO;
    using System.Runtime.CompilerServices;
    using System.Text;
    using System.Text.RegularExpressions;
    using System.Web;
    using Microsoft.Security.Application;

    internal class SEOFilter : Stream
    {
        private readonly Stream _stream;
        private string _topPageHiddenFields;
        private static readonly Regex Pattern = new Regex(@"^\s+", RegexOptions.Compiled | RegexOptions.Multiline);
        public SEOFilter(Stream stream)
        {
            try
            {
                this._stream = stream;
            }
            catch
            {
                throw;
            }
        }
        private string clearViewState(string html)
        {
            string str = "<input type=\"hidden\" name=\"__VIEWSTATE\" id=\"__VIEWSTATE\" value=\"";
            string str2 = "\" />";
            if (html.Contains(str))
            {
                int startIndex = html.IndexOf(str) + str.Length;
                if (startIndex < 0)
                {
                    return html;
                }
                int num3 = html.IndexOf(str2, startIndex) - startIndex;
                if ((num3 > 0) && (startIndex > 0))
                {
                    string oldValue = html.Substring(startIndex + 1, num3 - 1);
                    if (oldValue.Length > 0)
                    {
                        html = html.Replace(oldValue, string.Empty);
                    }
                }
            }
            return html;
        }
        public override void Close()
        {
            try
            {
                this._stream.Close();
            }
            catch
            {
                throw;
            }
        }
        private string ExtractPageTopHiddenFields(string html)
        {
            int index = html.IndexOf("<form");
            if (index >= 0)
            {
                int startIndex = html.IndexOf("<div", index);
                if (startIndex < 0)
                {
                    return html;
                }
                int num3 = html.IndexOf(">", startIndex);
                int num4 = num3 - startIndex;
                int num5 = html.IndexOf("</div", startIndex);
                if (num5 < 0)
                {
                    return html;
                }
                int num6 = html.IndexOf(">", num5);
                int length = (num5 - num3) - 1;
                if (html.Length > length)
                {
                    this._topPageHiddenFields = html.Substring(num3 + 1, length);
                    html = html.Remove(startIndex, (num6 - startIndex) + 1);
                }
            }
            return html;
        }
        public override void Flush()
        {
            try
            {
                this._stream.Flush();
            }
            catch
            {
                throw;
            }
        }
        private string getEncodedHTML(string html)
        {
            string str;
            try
            {
                StringBuilder builder = new StringBuilder(HttpUtility.HtmlEncode(html));
                builder = new StringBuilder(Regex.Replace(builder.Replace("&lt;b&gt;", "<b>").Replace("&lt;/b&gt;", "</b>").Replace("&lt;strong&gt;", "<strong>").Replace("&lt;/strong&gt;", "</strong>").Replace("&lt;i&gt;", "<i>").Replace("&lt;/i&gt;", "</i>").Replace("&lt;em&gt;", "<em>").Replace("&lt;/em&gt;", "</em>").Replace("&lt;u&gt;", "<u>").Replace("&lt;/u&gt;", "</u>").Replace("&lt;hr /&gt;", "<hr />").Replace("&lt;br&gt;", "<br />").Replace("&lt;br/&gt;", "<br />").Replace("&lt;br /&gt;", "<br />").ToString(), "&lt;img(.*?)/&gt;", "<img$1/>", RegexOptions.IgnoreCase));
                builder = new StringBuilder(Regex.Replace(builder.ToString(), "&lt;(div|span|table|tbody|thead|tr|th|td|font|ol|ul|li|a|p)(.*?)&gt;", "<$1$2>", RegexOptions.IgnoreCase));
                builder = new StringBuilder(Regex.Replace(builder.ToString(), "&lt;/(div|span|table|tbody|thead|tr|th|td|font|ol|ul|li|a|p)&gt;", "</$1>", RegexOptions.IgnoreCase));
                builder = new StringBuilder(Regex.Replace(builder.ToString(), "&lt;!--(.*?)--&gt;", ""));
                str = builder.Replace("&quot;", "\"").Replace("&amp;", "&").ToString();
            }
            catch
            {
                throw;
            }
            return str;
        }
        private string getSafeHTML(string html)
        {
            string str;
            try
            {
                html = Sanitizer.GetSafeHtml(html);
                str = html;
            }
            catch
            {
                throw;
            }
            return str;
        }
        private string getTrimmedHTML(string html)
        {
            string str;
            try
            {
                html = Regex.Replace(html, "[a-zA-Z]+#", "#");
                html = Regex.Replace(html, @"[\n\r]+\s*", string.Empty);
                html = Regex.Replace(html, @"\s+", " ");
                html = Regex.Replace(html, @"\s?([:,;{}])\s?", "$1");
                html = html.Replace(";}", "}");
                html = Regex.Replace(html, @"([\s:]0)(px|pt|%|em)", "$1");
                str = html;
            }
            catch
            {
                throw;
            }
            return str;
        }
        private string InsertExtractedHiddenFields(string html)
        {
            if (!string.IsNullOrEmpty(this._topPageHiddenFields))
            {
                int index = html.IndexOf("</form>");
                if (index > 0)
                {
                    html = html.Insert(index, this._topPageHiddenFields + Environment.NewLine);
                    this._topPageHiddenFields = null;
                }
            }
            return html;
        }
        private string moveHiddenFieldsToBottom(string html)
        {
            html = this.ExtractPageTopHiddenFields(html);
            html = this.InsertExtractedHiddenFields(html);
            return html;
        }
        public override int Read(byte[] buffer, int offset, int count)
        {
            int num;
            try
            {
                num = this._stream.Read(buffer, offset, count);
            }
            catch
            {
                throw;
            }
            return num;
        }
        public override long Seek(long offset, SeekOrigin origin)
        {
            long num;
            try
            {
                num = this._stream.Seek(offset, origin);
            }
            catch
            {
                throw;
            }
            return num;
        }
        public override void SetLength(long value)
        {
            try
            {
                this._stream.SetLength(value);
            }
            catch
            {
                throw;
            }
        }
        public override void Write(byte[] buffer, int offset, int count)
        {
            byte[] dst = new byte[count];
            Buffer.BlockCopy(buffer, offset, dst, 0, count);
            string html = Encoding.Default.GetString(buffer);
            html = this.getTrimmedHTML(html);
            html = this.clearViewState(html);
            html = this.moveHiddenFieldsToBottom(html);
            byte[] bytes = Encoding.Default.GetBytes(html);
            this._stream.Write(bytes, 0, bytes.GetLength(0));
        }

        public override bool CanRead
        {
            get
            {
                return true;
            }
        }
        public override bool CanSeek
        {
            get
            {
                return true;
            }
        }
        public override bool CanWrite
        {
            get
            {
                return true;
            }
        }    
        public override long Length
        {
            get
            {
                return 0L;
            }
        }
        public override long Position { get; set; }
    }
}

